﻿using System;
using System.IO;
using System.Text;
using System.Collections.Generic;
using Csu.Modsim.ModsimModel;
using Csu.Modsim.ModsimIO;
using ASquared.ModelOptimization; 

namespace iwpm.optimization
{
    public class HydroScenarioList : List<HydroScenario>, IScenarioTestable
    {
        #region Instance variables

        private bool _error = false;

        #endregion 

        #region Properties

        /// <summary>Gets whether an error occurred during simulation of any of the scenarios.</summary>
        public bool ErrorOccurred
        {
            get
            {
                return _error; 
            }
        }

        #endregion 

        #region Constructors 

        public HydroScenarioList()
            : base()
        {
        }
        public HydroScenarioList(List<HydroScenario> list)
            : base(list)
        {
        }

        #endregion

        #region Build MODSIM path from file 

        private static string _getModsimFilePath(StreamReader sr)
        {
            // Quick exit 
            if (sr.EndOfStream)
                return "";

            // Get the main xyfile path 
            string oldxyfile = "";
            do
            {
                oldxyfile = sr.ReadLine();
                if (oldxyfile.StartsWith("MODSIMFILE"))
                {
                    oldxyfile = oldxyfile.Split(HydroScenario.Delims)[1].Trim();
                    if (File.Exists(oldxyfile))
                        break;
                }
            }
            while (!sr.EndOfStream);
            return oldxyfile;
        }

        private static string _getOutputDirectory(StreamReader sr)
        {
            // Quick exit 
            if (sr.EndOfStream)
                return "";

            // Get the main xyfile path 
            string outdir = "";
            do
            {
                outdir = sr.ReadLine();
                if (outdir.StartsWith("OUTPUTDIR"))
                {
                    outdir = outdir.Split(HydroScenario.Delims)[1].Trim();
                    if (outdir.Equals(""))
                        return "";
                    if (!outdir.EndsWith("\\"))
                        outdir += "\\"; 
                    if (!Directory.Exists(outdir))
                        Directory.CreateDirectory(outdir);
                    return outdir; 
                }
            }
            while (!sr.EndOfStream);
            return "";
        }

        private static HydroScenarioList _getScenarios(StreamReader sr)
        {
            HydroScenarioList list = new HydroScenarioList();

            // Loop through solver scenarios on this file
            while (!sr.EndOfStream)
            {
                // Read the line and check if it's 
                string line = sr.ReadLine();
                if ((line = line.Trim()).Equals("") || line.StartsWith("Scenario_Name") || line.StartsWith("\\"))
                    continue;

                // Split the line
                HydroScenario scen = HydroScenario.FromString(line);
                if (scen != null)
                    list.Add(scen); 
            }

            return list;
        }

        /// <summary>Parses a HydroScenarioList from a file.</summary>
        /// <param name="file">The file containing the HydroScenarios</param>
        /// <returns>Returns a list of the HydroScenarios to solve.</returns>
        /// <remarks>The file must have these tab-delimited columns: Name, xyFile, scenarioLogFile, hydropowerWeight, tolerance, and maxIterations</remarks>
        public static HydroScenarioList FromFile(string file)
        {
            try
            {
                // initiallize variables 
                List<HydroScenario> list = new List<HydroScenario>();
                StreamReader sr = new StreamReader(file);

                // Get each HydroScenario from the file 
                list = _getScenarios(sr);

                // Close and create the HydroScenarioList 
                sr.Close();
                return new HydroScenarioList(list);

            }
            catch (Exception ex)
            {
                Console.WriteLine("Error occurred getting HydroScenarioList from file: \n" + ex.ToString());
                return null; 
            }
        }

        #endregion

        #region Write to file 

        /// <summary>Writes these scenarios to a file using a tab delimited format.</summary>
        /// <param name="file"></param>
        public void WriteToFile(string file)
        {
            try
            {
                StreamWriter sw = new StreamWriter(file);
                sw.Write(this.ToString());
                sw.Flush();
                sw.Close();
            }
            catch (Exception ex)
            {
                Console.WriteLine("Failed to write hydropower scenarios list to file.\n" + ex.ToString()); 
            }
        }

        public override string ToString()
        {
            StringBuilder s = new StringBuilder(); 
            return HydroScenario.Headers + "\n" 
                + string.Join("\n", Array.ConvertAll(this.ToArray(), scen => scen.ToString()));
        }

        #endregion 

        #region Solve 

        public void SolveAll()
        {
            SolveAll(false); 
        }

        /// <summary>Solves all the HydroScenarios sequentially</summary>
        /// <param name="logfile">The log file for each of the scenarios</param>
        public void SolveAll(bool writeLogs)
        {
            foreach (HydroScenario scen in this)
            {
                if (writeLogs)
                {
                    string basename = Path.GetDirectoryName(Path.GetFullPath(scen.ModelFilePath))
                        + "\\" + Path.GetFileNameWithoutExtension(scen.ModelFilePath);
                    scen.LogFilePath = basename + "_log.csv";
                    scen.DebugFilePath = basename + "_debug.csv"; 
                }

                scen.Solve();
                if (!_error)
                    _error = scen.ErrorOccurred; 
            }
        }

        #endregion 
    }
}
